package com.cmc.cloud.cmclink.doc.service.impl.multimodaltransport;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cmc.cloud.cmclink.doc.api.document.emums.ExImTypeEnum;
import com.cmc.cloud.cmclink.doc.api.document.emums.MulitOpOperationTypeEnum;
import com.cmc.cloud.cmclink.doc.constants.errorconstant.MultiOpErrorCodeConstants;
import com.cmc.cloud.cmclink.doc.convert.MultiOpConvert;
import com.cmc.cloud.cmclink.doc.entity.MultiOpDO;
import com.cmc.cloud.cmclink.doc.mapper.BlnoMapper;
import com.cmc.cloud.cmclink.doc.mapper.BlnoVslvoyMapper;
import com.cmc.cloud.cmclink.doc.mapper.MultiOpMapper;
import com.cmc.cloud.cmclink.doc.rpcservice.VoyScheduleService;
import com.cmc.cloud.cmclink.doc.service.multimodaltransport.MultiOpService;
import com.cmc.cloud.cmclink.doc.util.CostChargeUtil;
import com.cmc.cloud.cmclink.doc.util.VslvoyUtil;
import com.cmc.cloud.cmclink.doc.vo.multimodaltransport.multiop.*;
import com.cmc.cloud.cmclink.svl.api.base.enums.DateKindEnum;
import com.cmc.cloud.cmclink.svl.api.base.enums.SystemEnums;
import com.cmc.cloud.cmclink.svl.api.base.req.VoyQueryReqDTO;
import com.cmc.cloud.cmclink.svl.api.base.resp.VesselVoyRespDTO;
import com.cmc.cloud.cmclink.svl.api.base.resp.VoyQueryRespDTO;
import com.cmes.framework.common.exception.util.ServiceExceptionUtil;
import com.cmes.framework.common.pojo.PageResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


/**
 * 多式联运代理设置信息，发送邮件记录 Service 实现类
 *
 * @author 集运管理员
 */
@Service
@Validated
public class MultiOpServiceImpl implements MultiOpService {

    @Resource
    private MultiOpMapper multiOpMapper;
    @Resource
    BlnoVslvoyMapper blnoVslvoyMapper;
    @Resource
    BlnoMapper blnoMapper;
    @Resource
    private VslvoyUtil vslvoyUtil;
    @Resource
    private VoyScheduleService voyScheduleService;

    @Resource
    private CostChargeUtil costChargeUtil;
    @Override
    public void createMultiOp(MultiOpCreateReqVO createReqVO) {
        // 插入
        MultiOpDO multiOp = MultiOpConvert.INSTANCE.convert(createReqVO);
        multiOpMapper.insert(multiOp);
    }

    @Override
    public void updateMultiOp(MultiOpUpdateReqVO updateReqVO) {
        // 校验存在
        validateMultiOpExists(updateReqVO.getId());
        // 更新
        MultiOpDO updateObj = MultiOpConvert.INSTANCE.convert(updateReqVO);
        multiOpMapper.updateById(updateObj);
    }

    @Override
    public void deleteMultiOp(Long id) {
        // 校验存在
        validateMultiOpExists(id);
        // 删除
        multiOpMapper.deleteById(id);
    }

    private void validateMultiOpExists(Long id) {
        if (multiOpMapper.selectById(id) == null) {
            throw ServiceExceptionUtil.exception(MultiOpErrorCodeConstants.MULTI_OP_NOT_EXISTS);
        }
    }

    @Override
    public MultiOpDO getMultiOp(Long id) {
        return multiOpMapper.selectById(id);
    }

    @Override
    public List<MultiOpDO> getMultiOpList(Collection<Long> ids) {
        return multiOpMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<MultiOpDO> getMultiOpPage(MultiOpPageReqVO reqVO) {
        IPage<MultiOpDO> page = Page.of(reqVO.getPageNo(), reqVO.getPageSize());
        
        IPage<MultiOpDO> result = multiOpMapper.selectPageList(page, reqVO);
        return new PageResult<MultiOpDO>(result.getRecords(), result.getTotal());
    }

    @Override
    public PageResult<MultiOpCustomBrokerRespVO> pageCustomBroker(MultiOpCustomBrokerPageReqVO reqVO, ExImTypeEnum exImTypeEnum) {
        IPage<MultiOpDO> page = Page.of(reqVO.getPageNo(), reqVO.getPageSize());

        if (exImTypeEnum.isEx()) {
            IPage<MultiOpCustomBrokerRespVO> result = multiOpMapper.pageCustomBrokerEx(page,reqVO);
            return new PageResult<>(result.getRecords(), result.getTotal());
        }

        return new PageResult<>(new ArrayList<>(), 0L);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void setOp(List<Long> blnoIds, String content, String remark, String emailAddress, MulitOpOperationTypeEnum opOperationTypeEnum, ExImTypeEnum exImTypeEnum) {
        List<MultiOpDO> list = multiOpMapper.selectList(new LambdaQueryWrapper<MultiOpDO>()
                .in(MultiOpDO::getBlnoId, blnoIds)
                .eq(MultiOpDO::getImExType, exImTypeEnum.getValue())
                .eq(MultiOpDO::getOperationType, opOperationTypeEnum.getValue())
        );
        if(!list.isEmpty()){
            for (MultiOpDO multiOpDO : list) {
                multiOpDO.setContent(content);
                multiOpDO.setRemark(remark);
                multiOpDO.setEmailAddress(emailAddress);
            }
            multiOpMapper.updateBatch(list);
        }
        //不存在的新增
        List<Long> blnoIdsExist = list.stream().map(MultiOpDO::getBlnoId).collect(Collectors.toList());
        List<Long> blnoIdsNotExist = blnoIds.stream().filter(blnoId -> !blnoIdsExist.contains(blnoId)).collect(Collectors.toList());

        multiOpMapper.insertBatch(blnoIdsNotExist.stream().map(blnoId -> MultiOpDO.builder()
                .blnoId(blnoId)
                .imExType(exImTypeEnum.getValue())
                .operationType(opOperationTypeEnum.getValue())
                .content(content)
                .remark(remark)
                .remark(remark)
                .emailAddress(emailAddress)
                .build()
        ).collect(Collectors.toList()));

    }


    @Override
    public List<MultiOpCheckMsgReqVO> checkOp(List<Long> blnoIds, String content, MulitOpOperationTypeEnum opOperationTypeEnum, ExImTypeEnum exImTypeEnum) {
        if(StringUtils.isBlank(content)){
            List<MultiOpDO> list = multiOpMapper.selectList(new LambdaQueryWrapper<MultiOpDO>()
                    .in(MultiOpDO::getBlnoId, blnoIds)
                    .eq(MultiOpDO::getImExType, exImTypeEnum.getValue())
                    .eq(MultiOpDO::getOperationType, opOperationTypeEnum.getValue())
                    .and(wrapper -> wrapper
                            .isNotNull(MultiOpDO::getContent).or()
                            .eq(MultiOpDO::getContent, "")
                    )
            );
            if (list != null && !list.isEmpty()) {
                return list.stream().map(multiOpDO ->
                        new MultiOpCheckMsgReqVO(multiOpDO.getBlnoId() + "", "是否要清除原数据")).collect(Collectors.toList());
            }
        }
        return Collections.emptyList();
    }

    @Override
    public List<MultiOpSumRespVO> querySumByTime(MultiOpSumReqVO req) {
        List<MultiOpSumRespVO> result = new ArrayList<>(16);
        VoyQueryReqDTO voyQueryReqDTO = new VoyQueryReqDTO();
        voyQueryReqDTO.setDateKind(DateKindEnum.SEARCH_PERFORM.getLabel());
        voyQueryReqDTO.setPortCode(req.getPortCode());
        // 目前eta时间查询
        voyQueryReqDTO.setDateType("ETA");
        voyQueryReqDTO.setStartDate(req.getStartTime());
        voyQueryReqDTO.setEndDate(req.getEndTime());
        voyQueryReqDTO.setSystemNumber(SystemEnums.DOC.getSystemNumber());
        //查询船期数据
        List<VoyQueryRespDTO> list = voyScheduleService.listByCondition(voyQueryReqDTO);
        if (CollectionUtil.isEmpty(list)) {
            return result;
        }
        for (VoyQueryRespDTO voy : list) {
            MultiOpSumRespVO sum = new MultiOpSumRespVO();
            sum.setEta(StringUtils.isNotEmpty(voy.getEta()) ? voy.getEta() : voy.getPta());
            sum.setVesselCode(voy.getVesselCode());
            sum.setImVoy(voy.getImVoy());
            sum.setPortCode(voy.getPortCode());
            sum.setTerminalCode(voy.getTerminalCode());
            result.add(sum);
        }
        Map<String, MultiOpSumRespVO> vesselImMap = result.stream().collect(Collectors.toMap(e -> e.getVesselCode() + "_" + e.getImVoy(), e -> e, (o1, o2) -> o1));
        List<MultiOpSumQueryVO> blList = blnoVslvoyMapper.getBargeIm(req.getPortCode(), list);
        List<MultiOpSumQueryVO> validBlList = new ArrayList<>(16);

        if (CollectionUtil.isNotEmpty(blList)) {
            List<Long> lockBls = blnoMapper.findVoyageLockByBlIds(blList.stream().map(e -> e.getBlId()).collect(Collectors.toList()), ExImTypeEnum.EX.getValue());
            for (MultiOpSumQueryVO query : blList) {
                String key = query.getVesselCode() + "_" + query.getVoyageIm();
                MultiOpSumRespVO resp = vesselImMap.get(key);
                if (CollectionUtil.isNotEmpty(lockBls) && lockBls.contains(query.getBlId())) {
                    if (resp != null) {
                        validBlList.add(query);
                        resp.setBlCount(resp.getBlCount() == null ? 1 : resp.getBlCount() + 1);
                        if (StringUtils.isNotBlank(query.getVesselCodeTba()) && "TBA".equals(query.getVesselCodeTba()) == false) {
                            resp.setSetBargeVoyageCount(resp.getSetBargeVoyageCount() == null ? 1 : resp.getSetBargeVoyageCount() + 1);
                        }
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(validBlList)) {
                List<MultiOpSumQueryVO> blSumList = blnoVslvoyMapper.getBargeSum(validBlList.stream().map(e -> e.getVslvoyId()).collect(Collectors.toList()));
                if (CollectionUtil.isNotEmpty(blSumList)) {
                    for (MultiOpSumQueryVO sum : blSumList) {
                        String key = sum.getVesselCode() + "_" + sum.getVoyageIm();
                        MultiOpSumRespVO resp = vesselImMap.get(key);
                        if (resp != null) {
                            if (sum.getOperationType().equals(MulitOpOperationTypeEnum.BARGE.getValue())) {
                                resp.setSetBargeCount(sum.getOperationTypeCount());
                                resp.setEmailToBargeCount(sum.getEmailAddressCount());
                            }
                            if (sum.getOperationType().equals(MulitOpOperationTypeEnum.CUSTOM_BROKER.getValue())) {
                                resp.setSetCustomBrokerCount(sum.getOperationTypeCount());
                                resp.setEmailToCustomBrokerCount(sum.getEmailAddressCount());
                            }
                            if (sum.getOperationType().equals(MulitOpOperationTypeEnum.OPERATION_AGENT.getValue())) {
                                resp.setSetOperationAgentCount(sum.getOperationTypeCount());
                                resp.setEmailToOperationAgentCount(sum.getEmailAddressCount());
                            }
                        }
                    }
                }

            }
        }
        return result;
    }

    @Override
    public PageResult<MultiOpBargeAgentBrokerRespVO> imPageBargeAgentBroker(MultiOpBargeAgentBrokerPageReqVO pageVo) {
        IPage<MultiOpDO> page = Page.of(pageVo.getPageNo(), pageVo.getPageSize());

        IPage<MultiOpBargeAgentBrokerRespVO> result = multiOpMapper.imPageBargeAgentBroker(page, pageVo);
        //todo 批量查询
        String tsPort = pageVo.getTsPort();
        for (MultiOpBargeAgentBrokerRespVO record : result.getRecords()) {
            VesselVoyRespDTO vesselVoyRespDto = vslvoyUtil.getVesselVoyRespDTO(tsPort, record.getNextVoyage(), record.getNextVesselCode());
            if (vesselVoyRespDto !=null) {
                record.setEta(vesselVoyRespDto.getEta());
                record.setEtd(vesselVoyRespDto.getAtd());
            }

            Map<String, String> terminalMap = costChargeUtil.getVoyPortTerminalMap(record.getLinerLaneCode(), record.getLinerVoyage(), record.getLinerVesselCode());

            if (terminalMap != null) {
                //船期卸货码头
                record.setUnloadingTerminal(terminalMap.get(tsPort));
            }
        }
        return new PageResult<>(result.getRecords(), result.getTotal());

    }
}
